<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta http-equiv="Content-Language" content="zh-CN"><link href="stylesheet.css" media="all" rel="stylesheet" type="text/css">
<title>CREATE INDEX</title>
<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?d286c55b63a3c54a1e43d10d4c203e75"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script>
</head><body class="REFENTRY">
<div>
<table summary="Header navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><th colspan="5" align="center" valign="bottom">PostgreSQL 8.2.3 中文文档</th></tr>
<tr><td width="10%" align="left" valign="top"><a href="sql-creategroup.html" accesskey="P">后退</a></td><td width="10%" align="left" valign="top"><a href="sql-creategroup.html">快退</a></td><td width="60%" align="center" valign="bottom"></td><td width="10%" align="right" valign="top"><a href="sql-createlanguage.html">快进</a></td><td width="10%" align="right" valign="top"><a href="sql-createlanguage.html" accesskey="N">前进</a></td></tr>
</table>
<hr align="LEFT" width="100%"></div>
<h1><a name="SQL-CREATEINDEX"></a>CREATE INDEX</h1>
<div class="REFNAMEDIV"><a name="AEN47413"></a><h2>名称</h2>CREATE INDEX&nbsp;--&nbsp;定义一个新索引</div>
<a name="AEN47416"></a>
<div class="REFSYNOPSISDIV"><a name="AEN47418"></a><h2>语法</h2>
<pre class="SYNOPSIS">CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] <tt class="REPLACEABLE"><i>name</i></tt> ON <tt class="REPLACEABLE"><i>table</i></tt> [ USING <tt class="REPLACEABLE"><i>method</i></tt> ]
    ( { <tt class="REPLACEABLE"><i>column</i></tt> | ( <tt class="REPLACEABLE"><i>expression</i></tt> ) } [ <tt class="REPLACEABLE"><i>opclass</i></tt> ] [, ...] )
    [ WITH ( <tt class="REPLACEABLE"><i>storage_parameter</i></tt> = <tt class="REPLACEABLE"><i>value</i></tt> [, ... ] ) ]
    [ TABLESPACE <tt class="REPLACEABLE"><i>tablespace</i></tt> ]
    [ WHERE <tt class="REPLACEABLE"><i>predicate</i></tt> ]</pre>
</div>
<div class="REFSECT1"><a name="AEN47430"></a><h2>描述</h2>
<p><tt class="COMMAND">CREATE INDEX</tt> 在指定的表上创建一个名为 <tt class="REPLACEABLE"><i>index_name</i></tt> 的索引。索引主要用来提高数据库性能。但是如果不恰当的使用将导致性能的下降。</p>
<p>索引的键字字段是以字段名的方式声明的，或者是可选的写在一个圆括弧里面的表达式。如果索引方式支持多字段索引，那么也可以声明多个字段。</p>
<p>索引字段可以是一个使用一个或多个字段值进行计算的表达式。这个特性可用于获取对基本数据的某种变形的快速访问。比如，一个在 <tt class="LITERAL">upper(col)</tt> 上的函数索引将允许 <tt class="LITERAL">WHERE upper(col) = 'JIM'</tt> 子句使用索引。</p>
<p>PostgreSQL 为从索引提供 B-tree, hash, GiST, GIN 索引方法。用户也可以定义它们自己的索引方法，但这个工作相当复杂。</p>
<p>如果出现了 <tt class="LITERAL">WHERE</tt> 子句，则创建一个<i class="FIRSTTERM">部分索引</i>。部分索引是一个只包含表的一部分记录的索引，通常是该表中比其它部分数据更有用的部分。比如，如果你有一个表，里面包含已记账和未记账的定单，未记账的定单只占表的一小部分而且这部分是最常用的部分，那么你就可以通过只在未记账部分创建一个索引来改善性能。另外一个可能的用途是使用带有 <tt class="LITERAL">UNIQUE</tt> 的 <tt class="LITERAL">WHERE</tt> 强制一个表的某个子集的唯一性。参阅<a href="indexes-partial.html">节11.7</a>获取更多信息。</p>
<p><tt class="LITERAL">WHERE</tt> 子句里的表达式只能引用下层表的字段，它可以使用所有字段，而不仅仅是被索引的字段。目前，子查询和聚集表达式也不能出现在 <tt class="LITERAL">WHERE</tt> 子句里。</p>
<p>索引定义里的所有函数和操作符都必须是"immutable"(不变的)，也就是说，它们的结果必须只能依赖于它们的输入参数，而不能依赖任何外部的影响(比如另外一个表的内容或者当前时间)。这个限制可以确保该索引的行为是定义良好的。要在一个索引上或 <tt class="LITERAL">WHERE</tt> 中使用用户定义函数，请把它标记为 immutable 函数。</p>
</div>
<div class="REFSECT1"><a name="AEN47453"></a><h2>参数</h2>
<div class="VARIABLELIST">
<dl>
<dt><tt class="LITERAL">UNIQUE</tt></dt>
<dd><p>令系统在创建索引时(如果数据已经存在)和每次添加数据时检测表中是否有重复值。如果插入或更新的值会导致重复的记录时将生成一个错误。</p></dd>
<dt><tt class="LITERAL">CONCURRENTLY</tt></dt>
<dd><p>使用该选项后，PostgreSQL 将在创建索引的过程中不在表上持有任何防止插入、更改、删除的写入锁；否则将持有写入锁直到创建完成才释放。使用这个选项时有几个注意点，参见<a href="sql-createindex.html#SQL-CREATEINDEX-CONCURRENTLY"><i>并行创建索引</i></a>。</p></dd>
<dt><tt class="REPLACEABLE"><i>name</i></tt></dt>
<dd><p>要创建的索引名，不能包含模式名。索引总是在同一个模式中作为父表创建的。</p></dd>
<dt><tt class="REPLACEABLE"><i>table</i></tt></dt>
<dd><p>要索引的表名(可能有模式修饰)</p></dd>
<dt><tt class="REPLACEABLE"><i>method</i></tt></dt>
<dd><p>要使用的索引方法的名字。可选的名字是 <tt class="LITERAL">btree</tt>(缺省), <tt class="LITERAL">hash</tt>, <tt class="LITERAL">gist</tt>, <tt class="LITERAL">gin</tt></p></dd>
<dt><tt class="REPLACEABLE"><i>column</i></tt></dt>
<dd><p>表的列/字段名</p></dd>
<dt><tt class="REPLACEABLE"><i>expression</i></tt></dt>
<dd><p>一个基于该表的一个或多个字段的表达式。这个表达式通常必须带着圆括弧包围写出，如语法中显示那样。不过，如果表达式有函数调用的形式，那么圆括弧可以省略。</p></dd>
<dt><tt class="REPLACEABLE"><i>opclass</i></tt></dt>
<dd><p>一个关联的操作符类。参阅下文获取细节。</p></dd>
<dt><tt class="REPLACEABLE"><i>storage_parameter</i></tt></dt>
<dd><p>索引方法特定的存储参数的名字。参阅下文获取细节。</p></dd>
<dt><tt class="REPLACEABLE"><i>tablespace</i></tt></dt>
<dd><p>创建索引的表空间。如果没有声明，则使用 <a href="runtime-config-client.html#GUC-DEFAULT-TABLESPACE">default_tablespace</a> 表空间，如果 <tt class="VARNAME">default_tablespace</tt> 是空字符串，则使用数据库的缺省表空间。</p></dd>
<dt><tt class="REPLACEABLE"><i>predicate</i></tt></dt>
<dd><p>为一个部分索引定义约束表达式</p></dd>
</dl>
</div>
<div class="REFSECT2"><a name="SQL-CREATEINDEX-STORAGE-PARAMETERS"></a><h3>索引存储参数</h3>
<p><tt class="LITERAL">WITH</tt> 子句可以为索引指定<i class="FIRSTTERM">存储参数</i>。每个索引方法都可以有它自己的一套存储参数。内置的索引方法都都接受下面这个单独的参数：</p>
<div class="VARIABLELIST">
<dl>
<dt><tt class="LITERAL">FILLFACTOR</tt></dt>
<dd><p>一个索引的填充因子(fillfactor)是一个百分比，它表示创建索引时每个索引页的数据填充率。对于 B-trees 来说，意味着在创建索引时叶子页将按照此百分比填充数据，在右侧(最大的键值)扩展索引时同样也按照此百分比填充数据。如果后来某个页被完全填满，那么该页将被分割，从而导致索引性能退化。B-trees 默认的填充因子是 90 ，但是有效的取值范围是 10 到 100 。对于静态的不会发生改变的表，最佳值 100 可以让索引的物理体积最小，但是对于不断增长的表，较小的填充因子更合适，因为这将尽可能减少对页的分割。其它索引方法对填充因子的理解与此类似，但是其默认值各不相同。(译者注：如果有条件周期性的重建索引，那么建议使用较大的填充因子以减少索引的物理体积)</p></dd>
</dl>
</div>
</div>
<div class="REFSECT2"><a name="SQL-CREATEINDEX-CONCURRENTLY"></a><h3>并行创建索引</h3><a name="AEN47533"></a>
<p>创建索引的过程会对数据库的常规操作性能有不利影响。通常，在创建索引的时候 PostgreSQL 会锁定表以防止写入，然后对表做一次完整扫描以完成索引的创建。在此过程中其他事务仍然可以读取表，但是插入、更新、删除将被一直阻塞到索引创建完毕。这样做对于处于活跃状态的数据库可能会产生严重的性能影响。因为某些很大的表可能需要数个小时的时间来建立索引，而且即使对于生产中正在使用的较小的表，这种阻塞通常也是不可接受的。</p>
<p>PostgreSQL 允许在 <tt class="COMMAND">CREATE INDEX</tt> 创建索引时使用 <tt class="LITERAL">CONCURRENTLY</tt> 选项指定不锁定表。这样 PostgreSQL 就必须对表扫描两次，并且必须等待所有正在执行的事务完成。这种方法增加了总体工作量并且可能需要非常长的时间才能完成索引的创建。然而由于这种方法允许在创建索引的同时进行常规操作，因此这种方法适合于在运行过程中添加新索引。当然，创建索引所需要的额外 CPU 和 I/O 开销仍然会对其它操作有不利影响。</p>
<p>如果在对表进行第二次扫描的时候出现了问题，比如在唯一索引字段上出现了重复值，<tt class="COMMAND">CREATE INDEX</tt> 命令将会失败并遗留下一个"非法"的索引。这个"非法"索引将被忽略，因为它可能是不完整的，当然它也不会导致更新、插入、删除时的额外开销。在这种情况下推荐删除该索引然后尝试重新执行 <tt class="COMMAND">CREATE INDEX CONCURRENTLY</tt> 命令，另一种可能的方法是使用 <tt class="COMMAND">REINDEX</tt> 重建索引。由于 <tt class="COMMAND">REINDEX</tt> 不支持并行创建索引，因此可能不是一个好方法。</p>
<p>对于并行创建唯一索引还有一个警告：在开始对表进行第二次扫描的时候，已经在其他事务上强制进行唯一约束了。这意味着在索引创建完毕之前，如果有其它违反唯一约束的行为那么将会报错，甚至在索引最终创建失败的情况下也是如此。同样，如果在第二次扫描的过程中发生错误，生成的"非法"索引仍将在随后强制执行唯一约束的检查。</p>
<p>并行创建表达式索引和部分索引也是可以的。在表达式求值过程中发生的错误同样也会在唯一约束索引上导致类似前面描述过的行为。</p>
<p>在创建普通索引的同时还允许在同一张表上创建其他普通索引，但是在一张表上只能进行一个并行索引的创建。在此两种情况下，都不允许同时对表所在的模式进行修改。另一个差异是 <tt class="COMMAND">CREATE INDEX</tt> 可以放在一个事务块中执行，但 <tt class="COMMAND">CREATE INDEX CONCURRENTLY</tt> 不可以。</p>
</div>
</div>
<div class="REFSECT1"><a name="AEN47555"></a><h2>注意</h2>
<p>参阅<a href="indexes.html">章11</a>获取有关何时使用索引、何时不使用索引，以及索引在哪种情况下是有用的信息。</p>
<p>目前，只有 B-tree 和 GiST 索引方法支持多字段索引。缺省时最多可以声明 32 个键字(可以在编译 PostgreSQL 时修改)。目前只有 B-tree 支持唯一索引。</p>
<p>可以为索引的每个列/字段声明一个<i class="FIRSTTERM">操作符类</i>标识将要被该索引用于该列/字段的操作符。例如，一个四字节整数的 B-tree 索引将使用 <tt class="LITERAL">int4_ops</tt> 表；这个操作符类包括四字节整数的比较函数。实际上，该域的数据类型的缺省操作符类一般就足够了。某些数据类型有操作符类的原因是它们可能有多个有意义的顺序。例如，复数类型可能以绝对值或者实部排序。可以通过为该数据类型定义两个操作符类，然后在建立索引的时候选择合适的表来实现。有关操作符类更多的信息在<a href="indexes-opclass.html">节11.8</a>和<a href="xindex.html">节33.14</a>里。</p>
<p>使用 <a href="sql-dropindex.html"><i>DROP INDEX</i></a> 删除一个索引。</p>
<p>缺省时索引不会用于 <tt class="LITERAL">IS NULL</tt> 子句。这种场合下使用索引的最好方法是用 <tt class="LITERAL">IS NULL</tt> 谓词创建一个部分索引。</p>
<p>早先的 PostgreSQL 版本还有一个 R-tree 索引方法。因为它并不比 GiST 方法优秀，因此现在已经被删除了。如果指定了 <tt class="LITERAL">USING rtree</tt> 的话，<tt class="COMMAND">CREATE INDEX</tt> 将把它当作 <tt class="LITERAL">USING gist</tt> 看待，并将老的索引转化为 GiST 索引。</p>
</div>
<div class="REFSECT1"><a name="AEN47576"></a><h2>例子</h2>
<p>在表 <tt class="LITERAL">films</tt> 上的 <tt class="LITERAL">title</tt> 字段上创建一个 B-tree 索引：</p>
<pre class="PROGRAMLISTING">CREATE UNIQUE INDEX title_idx ON films (title);</pre>
<p>在表达式 <tt class="LITERAL">lower(title)</tt> 上创建一个索引以允许高效的大小写无关搜索：</p>
<pre class="PROGRAMLISTING">CREATE INDEX lower_title_idx ON films ((lower(title)));</pre>
<p>使用非默认的填充因子创建索引：</p>
<pre class="PROGRAMLISTING">CREATE UNIQUE INDEX title_idx ON films (title) WITH (fillfactor = 70);</pre>
<p>在表 <tt class="LITERAL">films</tt> 的 <tt class="LITERAL">code</tt> 字段上创建一个索引，并且让索引位于表空间 <tt class="LITERAL">indexspace</tt> 内：</p>
<pre class="PROGRAMLISTING">CREATE INDEX code_idx ON films(code) TABLESPACE indexspace;</pre>
<p>在不锁定表的情况下创建索引：</p>
<pre class="PROGRAMLISTING">CREATE INDEX CONCURRENTLY sales_quantity_index ON sales_table (quantity);</pre>
</div>
<div class="REFSECT1"><a name="AEN47594"></a><h2>兼容性</h2>
<p><tt class="COMMAND">CREATE INDEX</tt> 是 PostgreSQL 语言扩展。在 SQL 标准中没有这个命令。</p>
</div>
<div class="REFSECT1"><a name="AEN47599"></a><h2>又见</h2><a href="sql-alterindex.html"><i>ALTER INDEX</i></a>, <a href="sql-dropindex.html"><i>DROP INDEX</i></a></div>
<div>
<hr align="LEFT" width="100%">
<table summary="Footer navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td width="33%" align="left" valign="top"><a href="sql-creategroup.html" accesskey="P">后退</a></td><td width="34%" align="center" valign="top"><a href="index.html" accesskey="H">首页</a></td><td width="33%" align="right" valign="top"><a href="sql-createlanguage.html" accesskey="N">前进</a></td></tr>
<tr><td width="33%" align="left" valign="top">CREATE GROUP</td><td width="34%" align="center" valign="top"><a href="sql-commands.html" accesskey="U">上一级</a></td><td width="33%" align="right" valign="top">CREATE LANGUAGE</td></tr>
</table>
</div>
</body></html>